package org.oy.sealogger.ui;


import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;

import org.oy.sealogger.parser.CurrentState;
import org.oy.sealogger.parser.RMCSentence;
import org.oy.sealogger.route.GPSLocation;

import fileReader.demo.reader.Map;
import fileReader.demo.reader.MapLayer;

public class Boat implements Observer {

	// workaround
	private int counter = 0;
	/**
	 * 
	 */
	private static final long serialVersionUID = -4471940451592120644L;

	private AffineTransform rotator = null;
	private Point2D boatLocation = null;
	
	private Map map = null;
	private double boatLat = 0.0;
	private double boatLon = 0.0;
		
	private Vector<GPSLocation> sailingRoute = new Vector<GPSLocation>();
	private int change = 0;
	private boolean init = false;
	
	private Image boat;
	private ImageLoader imageLoader = new ImageLoader();
	private LoggerGraphics lg = null;
	
	private boolean alarmCircle;
	
	private double currentAngle = 0.0;

	private int boatX;
	private int boatY;
	private int boatWidth;
	private int boatHeight;
	
	private int screenW;
	private int screenH;
	
	public Boat(LoggerGraphics l, boolean alarmCircle) {
		this.lg = l;
		this.alarmCircle = alarmCircle;	
		boat = imageLoader.getImage("BOATnew.png");
	}
	
	public void draw(Graphics g, int screenW, int screenH, int bW, int bH, int space) {
		Graphics2D g2 = (Graphics2D)g;
		
		this.screenW = screenW;
		this.screenH = screenH;
		
		this.change = space;
		if (lg.getMap() == null)
			return;
		
		boatLocation = this.addMapPoint(g2,this.boatLat,this.boatLon);
		
		int boatW = bW;
		int boatH = bH;
		
		int x = (int)boatLocation.getX();
		int y = (int)boatLocation.getY();
		
		
		//FIXME	
		y += space;
		
		this.setVariables(x,y,boatW,boatH);
		
		Point p = this.getBoatCenter(x,y,boatW,boatH);	
			
		setBoatRotation(g2,this.currentAngle,p);
	
		g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f));
		g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
		g2.drawImage(boat,x,y,boatW,boatH, this.imageLoader);
			
		
		if (this.alarmCircle) {
			//double xAlarm = (double)this.getBoatCenter().x;
			//double yAlarm = (double)this.getBoatCenter().y;
			
			//x -= 30.0;
			//y -= 30.0;
	
			//g2.setPaint(Color.red);
			//g2.setStroke(new BasicStroke(3));
			//g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f));
			//this.alarm = new Ellipse2D.Double(x,y,60.0,60.0);
			//g2.draw(this.alarm);
		}

		
	}
	
	private void setVariables(int x, int y, int w, int h) {
		this.boatX = x;
		this.boatY = y;
		this.boatWidth = w;
		this.boatHeight = h;
	}
	
	public Point getBoatCenter(int x, int y, int w, int h) {
		Point p = new Point();
		
		int tempX = w / 2;
		int tempY = h / 2;
		p.x = (x + tempX);
		p.y = (y + tempY);
		
		return p;
	}


	public void setBoatRotation(Graphics2D g2, double angle, Point p) {
		//AffineTransform at;	
		this.rotator = new AffineTransform();	
		this.rotator.rotate(Math.toRadians(angle), p.x, p.y);
		g2.setTransform(this.rotator);
	}
	
	
	public void setCurrentAngle(double angle ) {
		this.currentAngle = angle;
		this.lg.repaint();
	}

	public void update(Observable state, Object arg) {
		//CurrentState cs = (CurrentState)state;
		RMCSentence rmc = ((CurrentState)state).getGPSLocation();
		this.setCurrentAngle(rmc.getTrack());
		
		this.boatLat = rmc.getLatitudeAsDouble();
		this.boatLon = rmc.getLongitudeAsDouble();
		
		if (this.init && counter > 5)
			this.sailingRoute.addElement(new GPSLocation(boatLon,boatLat));
		
		if (counter < 10) 
			counter++;
		
	}
	

	
	public Point2D addMapPoint(Graphics2D g2, double lat, double lon) {
		
		this.map = this.lg.getMap();
		
		Point2D p = null;
		
		Point2D start = null;
		Point2D end = null;
		
		double lastX = 0.0;
		double lastY = 0.0;
		
		
		if (this.map != null) {
			double a,b; // xy-pixels on screen
			
			double minX=MapLayer.getGlobalMin_x();
			double maxX=MapLayer.getGlobalMax_x();
			double minY=MapLayer.getGlobalMin_y();
			double maxY=MapLayer.getGlobalMax_y();
					
			//scalex and scaley has to be the same for all the layers to get right proportions
			//scalex and scaley makes the map fit the screen
			double scalex = 1600.0/(maxX-minX);	//adapt this to your screen
			double scaley = 900.0/(minY-maxY);	//adapt this to your screen
			
			double zoom = this.map.getZoom();
			double xtrans = this.map.getX_translation();
			double ytrans = this.map.getY_translation();			
			
			a = ((lon - minX)*(scalex))*zoom+xtrans;
			b = ((lat - minY)*(scaley)+900)*zoom+ytrans;
					
			
			for (int i = 0; i < this.sailingRoute.size(); i++) {
				GPSLocation location = this.sailingRoute.elementAt(i);
				double routeLon = location.getLongitude();
				double routeLat = location.getLatitude();
				
				double xr = ((routeLon - minX)*(scalex))*zoom+xtrans;
				double yr = ((routeLat - minY)*(scaley)+900)*zoom+ytrans;
				
				yr += this.change;
				yr += (this.boatWidth / 2);
				
				end = new Point2D.Double(xr,yr);
				
				if (lastX == 0 && lastY == 0) {
					lastX = xr;
					lastY = yr;
					start = new Point2D.Double(lastX,lastY);	
				} else {
					g2.setPaint(Color.ORANGE);
					g2.setStroke(new BasicStroke(2));
					g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f));
					g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
					
					//FIXME
					Line2D routeLine = new Line2D.Double(start,end);
					g2.draw(routeLine);
					
					start = end;
				}
				
			}


			if (this.lg.isBoatAutoCenterON()) {
				int ax = this.screenW / 2;
				int ay = this.screenH / 2;
				int tmp_transX = ax - (int)a;
				int tmp_transY = ay - (int)b;
				
				
				this.map.setX_translation(this.map.getX_translation()+tmp_transX);
				this.map.setY_translation(this.map.getY_translation()+tmp_transY);
		
			}
		
			p = new Point2D.Double(a,b);	
			this.init = true;			
		}
				
		return p;
	}
}
